/*
 * Copyright Hundsun Technologies Inc. All Rights Reserved.
 */

package genesisblock

import (
	"errors"

	"github.com/golang/protobuf/proto"
	clicommon "hundsun.com/hsl/hschain/cmd/cli/common"
	"hundsun.com/hsl/hschain/protos/common"
	"hundsun.com/hsl/hschain/protos/config"
	"hundsun.com/hsl/hschain/protos/ledger"
	"hundsun.com/hsl/hschain/protos/parachain"
)

//#####################子链共识相关#####################

// ValidatorGenesisBlockYamlConfig  采用Solo共识的创世块yaml文件对应的结构体
type ValidatorGenesisBlockYamlConfig struct {
	BaseGenesisBlockYamlConfig `yaml:",inline"`
	Consensus                  *ValidatorConsensusConfig
}

// ConvertToProtoMessage 在基类的基础上，解析了共识字段
func (d *ValidatorGenesisBlockYamlConfig) ConvertToProtoMessage() error {
	err := d.BaseGenesisBlockYamlConfig.ConvertToProtoMessage()
	if err != nil {
		return err
	}

	consensusConfigBytes, err := d.Consensus.Payload.ConvertToProtoMessageBytes()
	if err != nil {
		return err
	}

	d.genesisTxPayload.Consensus = &config.ConsensusConfig{
		Type:    parachain.ConsensusType,
		Payload: consensusConfigBytes,
	}

	err = d.genesisTxPayload.Validate()
	if err != nil {
		return err
	}
	return nil
}

// InitFromProtoMessage 在基类的基础上解析了consensus字段
func (d *ValidatorGenesisBlockYamlConfig) InitFromProtoMessage(genesisBlock *ledger.Block) error {
	err := d.BaseGenesisBlockYamlConfig.InitFromProtoMessage(genesisBlock)
	if err != nil {
		return err
	}
	d.Consensus = &ValidatorConsensusConfig{}
	d.Consensus.Type = parachain.ConsensusType
	d.Consensus.Payload = &ValidatorConsensusConfigPayload{}
	d.Consensus.Payload.InitFromProtoMessageBytes(d.genesisTxPayload.Consensus.Payload)
	return nil
}

//ValidatorConsensusConfig ...
type ValidatorConsensusConfig struct {
	BaseConsensusConfig `yaml:",inline"`
	Payload             *ValidatorConsensusConfigPayload `yaml:"payload"`
}

//ValidatorConsensusConfigPayload ...
type ValidatorConsensusConfigPayload struct {
	Validators []*clicommon.NetworkChainAccountConfig `yaml:"validators"`
}

//ConvertToProtoMessageBytes ...
func (v *ValidatorConsensusConfigPayload) ConvertToProtoMessageBytes() ([]byte, error) {

	if len(v.Validators) == 0 {
		return nil, errors.New("consensus.payload.validators[type=validator] not found or is empty")
	}
	pbPayload := &parachain.ConsensusConfigPayload{
		Validators: make([]*common.NetworkChainAccount, len(v.Validators)),
	}
	for i, m := range v.Validators {
		pbPayload.Validators[i] = &common.NetworkChainAccount{
			AccountAddress: m.Address,
			PeerID:         m.PeerID,
		}
	}
	err := pbPayload.Validate()
	if err != nil {
		return nil, err
	}
	pbPayloadBytes, err := proto.Marshal(pbPayload)
	if err != nil {
		return nil, err
	}
	return pbPayloadBytes, nil
}

//InitFromProtoMessageBytes ...
func (v *ValidatorConsensusConfigPayload) InitFromProtoMessageBytes(bytes []byte) error {
	pbConsensusConfigPayload := parachain.ConsensusConfigPayload{}
	err := proto.Unmarshal(bytes, &pbConsensusConfigPayload)
	if err != nil {
		return err
	}
	v.Validators = make([]*clicommon.NetworkChainAccountConfig, len(pbConsensusConfigPayload.Validators))
	for i, m := range pbConsensusConfigPayload.Validators {
		v.Validators[i] = &clicommon.NetworkChainAccountConfig{
			Address: m.AccountAddress,
			PeerID:  m.PeerID,
		}
	}
	return nil
}
